#!/usr/bin/env python

#################################################################################
#
# Copyright (c) 2006 Michigan State University
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#################################################################################

#################################################################################
#
#	Author:
#		Nathan Collins <npcollins@gmail.com>
#
#################################################################################

import re
import os

class terms_handler:
	def __init__(self, unproc):
		# the unprocessed search terms
		self.raw = unproc

		# return dictionary
		self.ret = {}
		self.ret['keywords'] = []
		self.ret['mTitle'] = ''
		self.ret['mCreator'] = ''
		self.ret['mDescription'] = ''
		self.ret['mSubject'] = ''
		self.retsafe = {}
		self.retsafe['keywords'] = []
		self.retsafe['mTitle'] = ''
		self.retsafe['mCreator'] = ''
		self.retsafe['mDescription'] = ''
		self.retsafe['mSubject'] = ''

		# match phrase
		self.sph = re.compile('(.*)"(.*? .*?)"(.*)')
		# match space
		self.ssp = re.compile(' ')
		# match escaped space
		self.ses = re.compile('\*~!SPACE!~\*')
		# match field
		self.sfi = re.compile('(.*) (\w+?):(.+?) (.*)')
		# match characters that should not be here anymore
		self.usd = re.compile('("|:)')
		# match invalid chars - for generating a safe search
		self.saf = re.compile(r'(\+|-|&&|\|\||!|\{|\}|\[|\]|\^|~|\*|\?|\\|\(|\))')

		# pre-process
		self.swapfields()

		# process
		self.proc_terms()

	def swapfields(self):
		"""
		using the 'relabels' file, map user entered fieldnames to lucene field names
		"""
		relabels = open('relabels','r')
		labels = relabels.readlines()
		relabels.close()
		
		for swap in labels:
			pair = swap.split('>')
			reswap = re.compile(pair[0] + ':')
			self.raw = reswap.sub(pair[1].strip() + ':',self.raw)

	def proc_terms(self):
		modterms = self.raw

		# handle spaces in quoted phrases
		m = self.sph.search(modterms)
		while m is not None:
			modterms = m.groups()[0] + self.ssp.sub('*~!SPACE!~*',m.groups()[1]) + m.groups()[2]
			m = self.sph.search(modterms)

		leftovers = ''

		# pad
		modterms = ' ' + modterms + ' '
		
		# field searches
		m = self.sfi.search(modterms)
		if m is None:
			leftovers = modterms
		while m is not None:
			termstr = self.ses.sub(' ', m.groups()[2])
			termstr = self.usd.sub('', termstr)
			fieldname = m.groups()[1]
			self.ret[fieldname] = termstr
			termstr = self.saf.sub('',termstr)
			self.retsafe[fieldname] = termstr

			# continue processing
			leftovers = ' ' + m.groups()[0] + ' ' + m.groups()[3]
			m = self.sfi.search(leftovers)

		kw = leftovers.split(' ')

		# remove blanks
		for w in kw:
			if len(w) > 0:
				termstr = self.ses.sub(' ',w)
				termstr = self.usd.sub('',termstr)
				self.ret['keywords'].append(termstr)
				termstr = self.saf.sub('',termstr)
				self.retsafe['keywords'].append(termstr)

	def get_terms(self):
		return self.ret

	def get_query_safe(self):
		return self.regenQuery(self.retsafe)

	def get_query(self):
		return self.regenQuery(self.ret)

	def regenQuery(self, terms):
		# regenerate the query from the parsed terms
		querybits = []

		for k,v in terms.iteritems():
			if len(v) > 0:
				# keyword field (default)
				if k == 'keywords':
					# loop the keywords
					for word in v:
						# if it is a phrase, read quotes
						if self.ssp.search(word) is not None:
							querybits.append('"'+ word +'"')
						else:
							querybits.append(word)

				# other fields
				else:
					# if it is a phrase, readd quotes
					if self.ssp.search(v) is not None:
						querybits.append(k+':"'+ v +'"')
					else:
						querybits.append(k+':'+v)

		# join and return
		return ' '.join(querybits)


# shorten field, with option to specify a minimum length
def shorten(s,l,m = 0):
	if l == 0: return s
	if len(s) < m: return ''
	if len(s) > l:
		return s[:l] + ' ...'
	else: return s

# clean up a title
def bad_url(searchStr):
	titleS1 = re.compile(r'^(.*)\s*--')
	titleS2 = re.compile(r'^(.*)\s*/')
	qr1 = titleS1.search(searchStr)
	if qr1 is not None and len(qr1.groups()[0].strip()) > 0:
		searchStr = qr1.groups()[0].strip()

	qr2 = titleS2.search(searchStr)
	if qr2 is not None and len(qr2.groups()[0].strip()) > 0:
		return qr2.groups()[0].strip()
	else:
		return searchStr

# make strings web safe
def webs(unsafe):
	sgt = re.compile('>')
	slt = re.compile('<')
	safe = unsafe.encode('ascii', 'xmlcharrefreplace')
	safe = sgt.sub('&gt;',safe)
	safe = slt.sub('&lt;',safe)
	return safe

#make URLs safe
def urls(unsafe):
	# should've used the python library - given a free moment, change it over
	sam = re.compile('&')
	ssp = re.compile(' ')
	squ = re.compile('"')
	srsb = re.compile('\]')
	slsb = re.compile('\[')
	ssc = re.compile(';')
	spd = re.compile('#')
	safe = sam.sub('%26',unsafe)
	safe = ssp.sub('+',safe)
	safe = squ.sub('%22',safe)
	safe = srsb.sub('%5d',safe)
	safe = slsb.sub('%5b',safe)
	safe = ssc.sub('%3b',safe)
	safe = spd.sub('%23',safe)
	return safe

def boldify(bolder, words):
	final = bolder
	# catch processing sinks
	if len(final) > 8192: return final
	try:
		for word in words:
			if len(word) > 0:
				bld = re.compile(u'\\b(%s)\\b' % (word), re.IGNORECASE | re.UNICODE)
				final = bld.sub(u'<b>\\1</b>',final)
	except:
		# errors shouldn't prevent page from displaying
		pass
	return final		

#eof

